package whf.framework.report.export;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.util.JRProperties;

import whf.framework.config.ApplicationConfig;
import whf.framework.log.Log;
import whf.framework.log.LogFactory;
import whf.framework.meta.entity.IMeta;
import whf.framework.report.export.exception.GenReportException;
import whf.framework.report.export.util.ExportUtils;
import whf.framework.report.export.view.AppletView;
import whf.framework.util.StringUtils;
import whf.framework.util.Utils;

/**
 * @author wanghaifeng
 * @create Dec 14, 2006 2:37:18 PM
 * 
 */
public class JasperExportHandler {
	private static Log log = LogFactory.getLog(JasperExportHandler.class);
	/**
	 * 编译临时目录
	 * @property String:compilerTempDir
	 */
	private String compilerTempDir;
	
	public JasperExportHandler(ServletContext context) throws ServletException {
		this.compilerTempDir = context.getRealPath(ApplicationConfig.getInstance().getValue(ExportUtils.EXPORT_FILES));
		File file = new File(this.compilerTempDir);
		if(file.exists() && file.isFile()){
			throw new ServletException("The specify dir is not a validate dir!");
		}
		if(!file.exists()){
			Utils.mkdir(this.compilerTempDir);
		}
		//
		JRProperties.setProperty(JRProperties.COMPILER_CLASSPATH, context.getRealPath("/WEB-INF/lib/jasperreports-1.0.1.jar")
				+ System.getProperty("path.separator") + context.getRealPath("/WEB-INF/classes/"));

		JRProperties.setProperty(JRProperties.COMPILER_TEMP_DIR, this.compilerTempDir);
	}

	public void service(HttpServletRequest request, HttpServletResponse response) throws Exception {
		Map<String, String> params = Utils.newHashMap();
		try {
			params = initParams(request);
			setReportClassName(params);
			genXmlReportFile(compilerTempDir, params);
			compileReport(compilerTempDir, params);
			JasperPrint jasperPrint = fillReport(compilerTempDir, params, ExportUtils.getDataSource());
			if (((String) params.get(ExportUtils.EXPORT_TYPE)).equals(ExportUtils.PDF)) {
				handlePdfView(jasperPrint, response);
			} else if (((String) params.get(ExportUtils.EXPORT_TYPE)).equals(ExportUtils.APPLET)) {
				handleAppletView(jasperPrint, response);
			} else if (((String) params.get(ExportUtils.EXPORT_TYPE)).equals(ExportUtils.XLS)) {
				handleXlsView(jasperPrint, response);
			}
		} catch (Exception ex) {
			log.error(this, ex);
			throw ex;
		}
	}

	/**
	 * 初始化参数
	 * 
	 * @param request
	 * @return
	 */
	protected Map<String, String> initParams(HttpServletRequest request) {
		Map<String, String> params = Utils.newHashMap();
		params.put(ExportUtils.EXPORT_TYPE, request.getParameter("et_"));
		params.put(ExportUtils.EXPORT_HEADER_TITLE, request.getParameter("title"));
		params.put(ExportUtils.REPORT_NAME, request.getParameter(ExportUtils.REPORT_NAME) + System.currentTimeMillis());
		return params;
	}

	/**
	 * 设置报表名称以及生成的class类名
	 * 
	 * @param params
	 * @param dbTableName
	 */
	protected void setReportClassName(final Map<String, String> params) {
		String className = null;
		IMeta meta = ExportUtils.getTableModel().getMeta();
		if(meta != null){
			String boClassName = "";
			if(meta instanceof whf.framework.meta.entity.Object){
				boClassName = ((whf.framework.meta.entity.Object)meta).getBoClassName();
			} else {
				boClassName = meta.getCode();
			}
			if(StringUtils.isEmpty(boClassName)){
				boClassName = "Class"+meta.getId();
			}
			className = ExportUtils.PREFIX_CLASS_NAME + boClassName;
		}
		params.put(ExportUtils.CLASS_NAME, className);
	}

	/**
	 * 生成.jrxml文件
	 * 
	 * @param path
	 * @param fileName
	 */
	public void genXmlReportFile(String filePath, Map<String, String> params)
			throws GenReportException, IOException {
		String fileName = filePath + File.separator + params.get(ExportUtils.REPORT_NAME) + ".jrxml";
		String fileNamejasper = filePath + File.separator + params.get(ExportUtils.REPORT_NAME) + ".jasper";
		File xmlFile = new File(fileName);

		if (xmlFile.exists()) {
			xmlFile.delete();
			File jasperFile = new File(fileNamejasper);
			jasperFile.delete();
		}
		AppletView appletView = new AppletView(ExportUtils.getTableModel(), params);
		appletView.beforeBody();
		appletView.doBody();
		String exportData = (String) appletView.afterBody();
		InputStream is = null;
		OutputStream out = null;
		try {
			is = new ByteArrayInputStream(exportData.getBytes("UTF-8"));
			out = new FileOutputStream(xmlFile);
			byte[] data = new byte[8192];
			int count = -1;
			while ((count = is.read(data)) != -1) {
				out.write(data, 0, count);
			}
		} catch (Exception ex) {
			throw new GenReportException("生成报表xml文件出错！", ex);
		} finally {
			if(is != null)
				is.close();
			if(out != null)
				out.close();
			exportData = null;
		}
	}

	/**
	 * 将.jrxml文件编译为.jasper文件
	 * 
	 * @param fileName
	 * @param context
	 */
	public void compileReport(String filePath, Map params) throws GenReportException {
		try {
			String fileName = filePath + File.separator + params.get(ExportUtils.REPORT_NAME) + ".jrxml";
			JasperCompileManager.compileReportToFile(fileName);
		} catch (Exception ex) {
			throw new GenReportException("编译报表文件出错！", ex);
		}

	}

	/**
	 * 填充报表
	 * 
	 * @param filePath
	 * @param params
	 * @param beans
	 * @return
	 */
	public JasperPrint fillReport(String filePath, Map params, Collection beans) throws GenReportException {
		JasperPrint jasperPrint = null;
		try {
			String fileName = filePath + File.separator + params.get(ExportUtils.REPORT_NAME) + ".jasper";
			jasperPrint = JasperFillManager.fillReport(fileName, null, new EntityCollectionDataSource(beans));
		} catch (Exception ex) {
			throw new GenReportException("填充报表出错！", ex);
		}
		return jasperPrint;
	}

	/**
	 * 输出appletView
	 * 
	 * @param response
	 * @param fileName
	 * @param beans
	 * @throws IOException
	 */
	public void handleAppletView(JasperPrint jasperPrint, HttpServletResponse response) throws IOException {
		if (jasperPrint != null) {
			response.setContentType("application/octet-stream");
			javax.servlet.ServletOutputStream ouputStream = response.getOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(ouputStream);
			oos.writeObject(jasperPrint);
			oos.flush();
			oos.close();
			ouputStream.flush();
			ouputStream.close();
		} else {
			response.setContentType("text/html;charset=GBK");
			PrintWriter out = response.getWriter();
			out.println("<html>");
			out.println("<body>");
			out.println("<span>打印失败</span>");
			out.println("</body>");
			out.println("</html>");
		}
	}

	/**
	 * 输出pdf文档
	 * 
	 * @param jasperPrint
	 * @param response
	 * @throws IOException
	 */
	public void handlePdfView(JasperPrint jasperPrint, HttpServletResponse response) throws IOException {
		String reportName = "export.pdf";
		try {
			if (jasperPrint != null) {
				byte[] bytes = JasperExportManager.exportReportToPdf(jasperPrint);
				response.setContentType("application/pdf;charset=UTF-8");
				response.setHeader("Content-disposition", "attachment; filename=" + reportName);
				response.setContentLength(bytes.length);
				ServletOutputStream ouputStream = response.getOutputStream();
				ouputStream.write(bytes, 0, bytes.length);
				ouputStream.flush();
				ouputStream.close();
			} else {
				response.setContentType("text/html;charset=GBK");
				PrintWriter out = response.getWriter();
				out.println("<html>");
				out.println("<body>");
				out.println("<span>打印失败</span>");
				out.println("</body>");
				out.println("</html>");
			}
		} catch (Exception ex) {
			log.error(this, ex);
		}
	}

	/**
	 * 输出xls文件
	 * 
	 * @param jasperPrint
	 * @param response
	 * @throws IOException
	 */
	public void handleXlsView(JasperPrint jasperPrint, HttpServletResponse response) throws IOException {
		String reportName = "export.xls";
		InputStream input = null;
		try {
			if (jasperPrint != null) {
				JRXlsExporter exporter = new JRXlsExporter();
				exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);

				exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, reportName);
				exporter.exportReport();
				File file = new File(this.compilerTempDir + File.separator + reportName);
				input = new FileInputStream(file);
				response.setContentType("application/vnd.ms-excel;charset=utf-8");
				response.setHeader("Content-disposition", "attachment; filename=" + reportName);
				ServletOutputStream ouputStream = response.getOutputStream();
				byte[] data = new byte[8192];
				int count = -1;
				int total = 0;
				while ((count = input.read(data)) != -1) {
					total += count;
					ouputStream.write(data, 0, count);
				}

				ouputStream.flush();
				ouputStream.close();
			} else {
				response.setContentType("text/html;charset=GBK");
				PrintWriter out = response.getWriter();
				out.println("<html>");
				out.println("<body>");
				out.println("<span>打印失败</span>");
				out.println("</body>");
				out.println("</html>");
			}
		} catch (Exception ex) {
			log.error(this, ex);
		} finally {
			input.close();
		}
	}

	/**
	 * 判断文件是否存在
	 * 
	 * @param fileName
	 * @return
	 */
	protected boolean isFileExists(String filePath, Map params) {
		String fileName = filePath + File.separator
				+ params.get(ExportUtils.REPORT_NAME) + ".jasper";
		File jasperFile = new File(fileName);
		return jasperFile.exists();
	}
}